package com.dycx.api.config;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.dycx.common.RestResponse;
import com.dycx.common.annotation.Authorization;
import com.dycx.common.annotation.WriterLog;
import com.dycx.common.context.UserInfoContext;
import com.dycx.user.service.UserAuthService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 统一日志处理切面
 */
@Aspect
@Component
@Order(2)
public class AuthUserAspect {

    @Autowired
    private UserAuthService userAuthService;

    @Pointcut("execution(public * com.dycx.api.controller.app.*.*.*(..))")
    private void userInfo() {
    }

    @Pointcut("execution(public * com.dycx.api.controller.app.*.*(..))")
    private void userInfo2() {
    }

    //定义切点表达式,指定通知功能被应用的范围
    @Pointcut("userInfo() || userInfo2()")
    private void auth() {
    }

    @Before("auth()")
    private void doBefore(JoinPoint joinPoint) throws Throwable {
    }

    /**
     * value切入点位置
     * returning 自定义的变量，标识目标方法的返回值,自定义变量名必须和通知方法的形参一样
     * 特点：在目标方法之后执行的,能够获取到目标方法的返回值，可以根据这个返回值做不同的处理
     */
    @AfterReturning(value = "auth()", returning = "ret")
    private void doAfterReturning(Object ret) throws Throwable {
//        System.out.println("9999999999999999999999");
    }

    //通知包裹了目标方法，在目标方法调用之前和之后执行自定义的行为
    //ProceedingJoinPoint切入点可以获取切入点方法上的名字、参数、注解和对象
    @Around("auth()")
    private Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {

        //获取当前请求对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        //鉴权
        RestResponse<String> res = RestResponse.success();
        if (method.isAnnotationPresent(Authorization.class)) {
            res = userAuthService.auth(request);
            if (!res.isSuccess()) return res;
        }

        //************************************执行前************************************************

        //前面是前置通知，后面是后置通知
        Object result = joinPoint.proceed();

        //************************************执行后************************************************

        RestResponse restResponse = BeanUtil.toBean(result, RestResponse.class);
        restResponse.setRefreshToken(res.data);

        //移除单进程存储登录信息，防止内存泄漏
        UserInfoContext.remove();

        return restResponse;
    }
}
